<?php

declare(strict_types=1);

namespace sheep\console;

use think\console\input\Argument;
use think\console\input\Option;
use think\facade\Config;
use Exception;
use sheep\traits\Helper;
use sheep\traits\ConfigSet;
use sheep\exception\SheepException;
use sheep\library\console\Composer as ComposerProcess;
use sheep\library\install\Install;


class SheepInstall extends Command
{
    use Helper, ConfigSet;

    protected $install = null;

    protected $commonCb = null;

    /**
     * 支持的命令列表
     */
    protected $commands = [
        ['code' => "0", 'name' => 'cancel', 'desc' => '已取消'],
        ['code' => "1", 'name' => 'init', 'desc' => '安装'],
        ['code' => "2", 'name' => 'check_system_env', 'desc' => '检查系统环境'],
        ['code' => "3", 'name' => 'database_config', 'desc' => '配置并检查数据库'],
        ['code' => "4", 'name' => 'redis_config', 'desc' => '配置并检查 redis'],
        ['code' => "5", 'name' => 'database_migrate', 'desc' => '执行数据库迁移'],
        ['code' => "6", 'name' => 'database_seed', 'desc' => '执行系统必要数据填充'],
        ['code' => "7", 'name' => 'application_config', 'desc' => '初始化应用'],
        ['code' => "8", 'name' => 'permission', 'desc' => '更新权限'],
    ];

    protected function configure()
    {
        $this->setName('sheep:install')
            ->addArgument('code', Argument::OPTIONAL, "请输入操作编号")
            ->setDescription('安装 sheep admin');

        // 设置初始化方法
        $this->commonCb = function ($input, $output) {
            $this->install = new Install($output);
        };
    }



    /**
     * 安装
     */
    protected function init() 
    {
        // 开始安装，输出 logo 说明
        $this->install->outputIntro();

        $this->permission();        

        // 检查系统配置
        $this->checkSystemEnv();

        // 生成 jwt secret
        $key = $this->install->setJwtKey();
        if ($key) {
            $this->output->writeln(sprintf('JWT_SECRET [%s] set successfully.', $key));
        }

        // 安装 扩展包 
        // $this->updatePackages();

        // 数据库配置和检测
        $this->databaseConfig();
        // redis 配置和检测
        $this->redisConfig();

        // 数据迁移
        $this->databaseMigrate();

        // 初始数据填充，非测试数据
        $this->databaseSeed();

        // 到这里就算安装成功了，写入 install.lock 文件
        $this->install->writeInstallLock();

        // 应用初始设置
        $this->applicationConfig();

        $this->install->success();

        $this->install->outputOutro();
    }


    protected function permission()
    {
        // 修改权限
        if (strpos(strtolower(PHP_OS), 'linux') === false) {
            // 非 linux 服务器，跳过权限修改
            $this->install->moduleEnd('[ok] 非 linux 系统，跳过权限更新');
            return true;
        }

        $this->install->moduleStart('开始更新项目权限');

        $this->output->writeln('请填写 phpfpm 进程启动用户名');
        $username = $this->output->ask(
            $this->input,
            'linux 用户名，宝塔环境默认为 www 用户',
            'www'
        );

        $this->output->writeln('请填写 lnmp 环境用户组名');
        $group = $this->output->ask(
            $this->input,
            'lnmp 用户组名，宝塔环境默认为 www 用户组',
            'www'
        );

        $this->install->permission($username, $group);

        $this->install->moduleEnd('[ok] 权限更新成功');
    }


    /**
     * 检查环境
     */
    protected function checkSystemEnv() {
        $this->install->moduleStart('开始检测系统环境');

        $result = $this->install->checkSystemEnv();

        if ($result['error']) {
            throw new SheepException('[error] 请先将上面 [no] 开头的项配置好再重试');
        }
        $this->install->moduleEnd('[ok] 环境检测完成');
    }



    /**
     * 更新 composer 扩展包
     */
    protected function updatePackages()
    {
        $this->install->moduleStart('开始更新 composer 扩展包');
        $result = $this->install->updatePackages();
        $this->install->moduleEnd('[ok] composer 扩展包更新成功');
    }


    /**
     * setDatabaseConfig 设置数据库账号密码
     */
    protected function databaseConfig()
    {
        // 数据库配置
        $this->install->moduleStart('开始数据库配置');

        // 设置数据库账号密码
        $this->setDatabase();

        try {
            // 检测是否配置成功
            $this->install->checkDatabase();

            $this->install->moduleEnd('[ok] 数据库配置成功');
        } catch (Exception $ex) {
            $this->output->error('[error] ' . $ex->getMessage());
            $this->install->refreshEnvVars();
            return $this->databaseConfig();
        }
    }


    /**
     * 设置数据库账号密码
     */
    protected function setDatabase()
    {
        // 请填写 mysql 连接地址
        $this->output->writeln('请填写 mysql 连接地址');
        $host = $this->output->ask(
            $this->input,
            'mysql 连接地址',
            env('DATABASE.HOSTNAME', 'localhost')
        );
        $this->install->setEnvVar('DATABASE.HOSTNAME', $host);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.hostname', $host);

        // 请填写 mysql 端口号
        $this->output->writeln("请填写 mysql 端口号");
        $port = $this->output->ask(
            $this->input,
            'mysql 端口号',
            env('DATABASE.HOSTPORT', 3306)
        );
        $this->install->setEnvVar('DATABASE.HOSTPORT', $port);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.hostport', $port);

        // 请填写数据库名
        $this->output->writeln("请填写数据库名，不存在将自动创建");
        $database = $this->output->ask(
            $this->input,
            '数据库名',
            env('DATABASE.DATABASE', 'sheep')
        );
        $this->install->setEnvVar('DATABASE.DATABASE', $database);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.database', $database);

        // 请填写数据库表前缀
        $this->output->writeln("请填写数据库表前缀");
        $database = $this->output->ask(
            $this->input,
            '数据库表前缀',
            env('DATABASE.PREFIX', 'fa_')
        );
        $this->install->setEnvVar('DATABASE.PREFIX', $database);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.prefix', $database);

        // 请填写数据库连接账号
        $this->output->writeln("请填写数据库连接账号");
        $username = $this->output->ask(
            $this->input,
            '数据库连接账号',
            env('DATABASE.USERNAME', 'root')
        );
        $this->install->setEnvVar('DATABASE.USERNAME', $username);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.username', $username);

        // 请填写数据库连接密码
        $this->output->writeln("请填写数据库连接密码");
        $password = $this->output->ask(
            $this->input,
            '数据库连接密码',
            env('DATABASE.PASSWORD', '')
        );
        $this->install->setEnvVar('DATABASE.PASSWORD', $password);
        // 更新配置值
        $this->install->setConfig('database.connections.mysql.password', $password);
    }



    /**
     * setupDatabaseConfig requests the database engine
     */
    protected function redisConfig()
    {
        // redis 配置
        $this->install->moduleStart('开始 redis 配置');

        $answer = $this->output->confirm(
            $this->input,
            "现在配置 redis？"
        );

        if (!$answer) {
            $this->install->moduleEnd('[ok] 跳过 redis 配置');
            return true;
        }

        // 设置 redis 账号密码
        $this->setRedis();

        try {
            // 检测是否配置成功
            $this->install->checkRedis();

            $this->install->moduleEnd('[ok] redis 配置成功');
        } catch (Exception $ex) {
            $this->output->error('[error] ' . $ex->getMessage());
            $this->install->refreshEnvVars();
            return $this->redisConfig();
        }
    }


    /**
     * 设置 redis 账号密码
     */
    protected function setRedis()
    {
        // 请填写 redis 连接地址
        $this->output->writeln('请填写 redis 连接地址');
        $host = $this->output->ask(
            $this->input,
            'redis 连接地址',
            env('REDIS.REDIS_HOST', 'localhost')
        );
        $this->install->setEnvVar('REDIS.REDIS_HOST', $host);
        // 更新配置值
        $this->install->setConfig('redis.host', $host);

        // 请填写 redis 端口号
        $this->output->writeln("请填写 redis 端口号");
        $port = $this->output->ask(
            $this->input,
            'redis 端口号',
            env('REDIS.REDIS_PORT', 6379)
        );
        $this->install->setEnvVar('REDIS.REDIS_PORT', $port);
        // 更新配置值
        $this->install->setConfig('redis.port', $port);

        // 请填写 redis 连接密码
        $this->output->writeln("请填写 redis 连接密码");
        $password = $this->output->ask(
            $this->input,
            'redis 连接密码',
            env('REDIS.REDIS_PASSWORD', '')
        );
        $this->install->setEnvVar('REDIS.REDIS_PASSWORD', $password);
        // 更新配置值
        $this->install->setConfig('redis.password', $password);

        // 请填写数据库名
        $this->output->writeln("请填写 redis db 库 1-15");
        $select = $this->output->ask(
            $this->input,
            'redis db 库',
            env('REDIS.REDIS_SELECT', 1)
        );
        $this->install->setEnvVar('REDIS.REDIS_SELECT', $select);
        // 更新配置值
        $this->install->setConfig('redis.connections.default.select', $select);
        $this->install->setConfig('redis.connections.queue.select', $select);
        $this->install->setConfig('redis.connections.session.select', $select);

        // 更新 redis 配置
        $this->coverRedisConfig();
    }


    /**
     * 数据迁移
     */
    protected function databaseMigrate() {
        // 数据库初始化
        $this->install->moduleStart('开始执行数据迁移');
        $result = $this->install->databaseMigrate();
        if (!$result['error']) {
            $this->install->moduleEnd('[ok] 数据迁移执行成功');
        } else {
            $this->output->error('[error] 数据迁移执行失败，请手动执行以下命令');
            $this->output->writeln('php think migrate:run');

            throw new SheepException('[error] 数据迁移执行失败');
        }
    }



    /**
     * 初始数据填充,非测试数据
     */
    protected function databaseSeed()
    {
        // 数据库填充
        $this->install->moduleStart('开始执行数据填充');

        // 执行数据填充
        $result = $this->install->databaseSeed();
        
        if (!$result['error']) {
            $this->install->moduleEnd('[ok] 数据填充执行成功');
        } else {
            $this->output->newLine();
            $this->output->error('[error] 数据填充执行失败，请手动执行以下命令');
            $this->output->newLine();

            foreach ($result['statusItem'] as $item) {
                if ($item['error']) {
                    $this->output->writeln('php think seed:run --seed=' . $item['item']);
                }
            }
            throw new SheepException('[error] 数据填充执行失败');
        }
    }



    /**
     * 后台应用设置
     */
    protected function applicationConfig()
    {
        // 为了应用的安全，请使用自定义地址访问管理面板
        $this->install->moduleStart('后台初始设置');
        // $backendUri = $this->output->ask(
        //     $this->input,
        //     '管理面板入口 [为了应用的安全，请使用自定义地址访问管理面板]',
        //     env('APP.BACKEND_URI', '/backend')
        // );
        // $this->install->setEnvVar('APP.BACKEND_URI', $backendUri);

        // 管理员账号
        $account = $this->output->ask(
            $this->input,
            '请设置管理员账号',
            'admin'
        );

        // 管理员密码
        $password = $this->output->ask(
            $this->input,
            '请设置管理员密码',
            '123456'
        );

        // 创建管理员账号，并设置为超级管理员
        $result = $this->install->createAdmin($account, $password);

        if (!$result) {
            $this->output->warning('[warning] 管理员账号已存在，如忘记密码，可以使用 php think sheep:help admin_reset_password 重置密码');
        }

        $this->install->moduleEnd('[ok] 初始配置成功');
    }
}
